#pragma once

#include <fstream>
#include <iostream>
#include <string>
#include <vector>

namespace xy
{

namespace render
{

struct color_t
{
    std::uint8_t bgra[4];

    color_t(std::uint32_t argb);
    color_t(std::uint8_t R, std::uint8_t G, std::uint8_t B, std::uint8_t A);
    color_t(const std::uint8_t *p, std::size_t bpp);

    color_t operator+(const color_t &other) const;
    color_t operator*(float t) const;
    operator std::uint32_t() const;

    /**
     * @brief
     *
     * @param fg
     * @param bg
     * @return color_t
     */
    static color_t alpha(const color_t &fg, const color_t &bg);
};

struct image_t
{
  private:
    struct _impl
    {
        std::vector<std::uint8_t> data;
        std::size_t width, height, bpp;

        _impl() = default;
        _impl(std::size_t width, std::size_t height, std::size_t bpp)
            : data(width * height * bpp, 0), width(width), height(height), bpp(bpp)
        {
        }
    };

    std::shared_ptr<_impl> m_impl;

  public:
    image_t();
    image_t(std::size_t width, std::size_t height, std::size_t bpp);
    _impl *operator->() const noexcept;

    color_t get(std::size_t x, std::size_t y) const;
    void set(std::size_t x, std::size_t y, const color_t &c);
    color_t safe_get(std::size_t x, std::size_t y, const color_t &c) const;
    void safe_set(std::size_t x, std::size_t y, const color_t &c);

    void invert_rgb();
    void flip_vertically();
    void flip_horizontally();
    void resize(std::size_t width, std::size_t height);
    void read(std::string filename);
    void write(std::string filename) const;
    image_t half_image() const;
};

template <std::size_t N> struct mipmap_t
{
    std::array<image_t, N> images;

    mipmap_t() = default;
    mipmap_t(const image_t &image)
    {
        // 自动生成 mipmap，效果不好说
        images[0] = image;
        for (std::size_t i = 1; i < N; i++)
            images[i] = images[i - 1].half_image();
    }
};

} // namespace render

} // namespace xy
